
<?php
// API for task_manager using PDO to avoid accidental HTML error output
ini_set('display_errors', '0');
error_reporting(0);
header('Content-Type: application/json; charset=utf-8');
session_start();

$root = __DIR__ . DIRECTORY_SEPARATOR . 'config.json';
$cfg = file_exists($root) ? json_decode(file_get_contents($root), true) : [];
$dbRootPwd = $cfg['db_root_password'] ?? '';

function json_ok($data = []){ echo json_encode(array_merge(['ok'=>true], $data)); exit; }
function json_err($msg='error', $code=400){ http_response_code($code); echo json_encode(['ok'=>false,'error'=>$msg]); exit; }

// create PDO connection
// debug flag: set true to include exception messages in JSON responses (development only)
$DEBUG = true;
try{
    $pdo = new PDO('mysql:host=127.0.0.1;dbname=task_manager;charset=utf8mb4', 'root', $dbRootPwd, [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::ATTR_EMULATE_PREPARES => false,
    ]);
}catch(Exception $e){
    error_log('DB connect error: '.$e->getMessage());
    if ($DEBUG) json_err('db_connect_failed: '.$e->getMessage(),500);
    json_err('db_connect_failed',500);
}

$action = $_GET['action'] ?? '';
$input = json_decode(file_get_contents('php://input'), true) ?: [];

// helper: require logged-in user
function require_login(){
    if (!isset($_SESSION['user'])) json_err('unauthorized',401);
}

// session info
if ($action === 'session'){
    if (!isset($_SESSION['user'])) json_ok(['session'=>null]);
    json_ok(['session'=>$_SESSION['user']]);
}

// login
if ($action === 'login' && $_SERVER['REQUEST_METHOD'] === 'POST'){
    $wechat = $input['wechat'] ?? '';
    $password = $input['password'] ?? '';
    if (!$wechat || !$password) json_err('missing',400);
    $stmt = $pdo->prepare('SELECT id,nickname,password FROM users WHERE wechat_id = ? LIMIT 1');
    $stmt->execute([$wechat]);
    $u = $stmt->fetch();
    if (!$u) json_err('no user',401);
    $ok = false;
    if (!empty($u['password']) && password_verify($password, $u['password'])) $ok = true;
    if ($password === $u['password']) $ok = true; // backwards compatibility for plain-text
    if (!$ok) json_err('invalid',401);
    $_SESSION['user'] = ['id'=>$u['id'],'wechat'=>$wechat,'nickname'=>$u['nickname']];
    // set persistent session cookie (remember me) - 30 days
    $cookie_name = session_name();
    $cookie_value = session_id();
    $expiry = time() + 30*24*3600; // 30 days
    // path '/', no secure flag (local dev), HttpOnly true
    setcookie($cookie_name, $cookie_value, $expiry, '/');
    json_ok(['nickname'=>$u['nickname']]);
}

// logout
if ($action === 'logout' && $_SERVER['REQUEST_METHOD'] === 'POST'){
    // destroy session server-side
    $_SESSION = [];
    if (ini_get('session.use_cookies')){
        $params = session_get_cookie_params();
        setcookie(session_name(), '', time() - 42000, $params['path'], $params['domain'], $params['secure'], $params['httponly']);
    }
    session_destroy();
    json_ok([]);
}

// register
if ($action === 'register' && $_SERVER['REQUEST_METHOD'] === 'POST'){
    $wechat = $input['wechat'] ?? '';
    $nickname = $input['nickname'] ?? '';
    $password = $input['password'] ?? '';
    if (!$wechat || !$password) json_err('missing',400);
    $allowed = $cfg['allowed_users'] ?? [];
    $isAllowed = false; $defaultNick = $wechat;
    if (is_array($allowed)){
        // indexed list of wechat ids
        if (in_array($wechat, $allowed, true)) $isAllowed = true;
    }elseif(is_array($allowed) || is_object($allowed)){
        if (isset($allowed[$wechat])){ $isAllowed = true; if (is_array($allowed[$wechat]) && isset($allowed[$wechat]['nickname'])) $defaultNick = $allowed[$wechat]['nickname']; elseif (is_string($allowed[$wechat])) $defaultNick = $allowed[$wechat]; }
    }
    if (!$isAllowed) json_err('not allowed',403);
    $hash = password_hash($password, PASSWORD_DEFAULT);
    $stmt = $pdo->prepare('INSERT INTO users (nickname,wechat_id,password) VALUES (?,?,?)');
    try{ $stmt->execute([$nickname,$wechat,$hash]); } catch(Exception $e){ json_err('insert_failed',500); }
    json_ok([]);
}

// list users
if ($action === 'users'){
    require_login();
    $stmt = $pdo->query('SELECT id,nickname,wechat_id FROM users');
    $rows = $stmt->fetchAll();
    json_ok(['users'=>$rows]);
}

// list labors (include user nickname if available)
if ($action === 'labors'){
    require_login();
    // left join users to include nickname for each labor's worker_wechat
    // support optional server-side filtering by start_dt and end_dt (YYYY-MM-DD HH:MM:SS)
    $start = isset($_GET['start_dt']) ? trim($_GET['start_dt']) : null;
    $end = isset($_GET['end_dt']) ? trim($_GET['end_dt']) : null;
    $params = [];
    $where = '';
    if ($start !== null && $end !== null && $start !== '' && $end !== ''){
        // include labors that start or end inside the range or fully span the range
        $where = 'WHERE ( (l.start_at BETWEEN ? AND ?) OR (l.end_at BETWEEN ? AND ?) OR (l.start_at < ? AND l.end_at > ?) )';
        $params = [$start, $end, $start, $end, $start, $end];
    }
    // default: no filter
    $sql = 'SELECT l.*, u.nickname AS nickname FROM labors l LEFT JOIN users u ON l.worker_wechat = u.wechat_id ' . $where . ' ORDER BY l.start_at DESC';
    if (empty($params)){
        $stmt = $pdo->query($sql);
    }else{
        $stmt = $pdo->prepare($sql);
        $stmt->execute($params);
    }
    $rows = $stmt->fetchAll();
    json_ok(['labors'=>$rows]);
}

// create labor
if ($action === 'create_labor' && $_SERVER['REQUEST_METHOD'] === 'POST'){
    require_login();
    $name = $input['name'] ?? '';
    $worker = $input['worker_wechat'] ?? ($input['worker'] ?? ($input['wechat'] ?? ''));
    $weight = isset($input['weight']) ? floatval($input['weight']) : 1.0;
    $points = isset($input['points']) ? floatval($input['points']) : 0.0;

    // normalize start_at/end_at to Beijing time (Asia/Shanghai) so DB matches displayed time
    $tz = new DateTimeZone('Asia/Shanghai');
    $nowBeijing = new DateTime('now', $tz);
    if (!empty($input['start_at'])){
        $raw = $input['start_at'];
        if (preg_match('/[zZ]|[+\-]\d{2}:?\d{2}$/', $raw)){
            $dt = new DateTime($raw);
            $dt->setTimezone($tz);
        }else{
            // assume the provided time without tz is already local Beijing time
            $dt = new DateTime($raw, $tz);
        }
        $start_at = $dt->format('Y-m-d H:i:s');
    }else{
        $start_at = $nowBeijing->format('Y-m-d H:i:s');
    }
    if (array_key_exists('end_at', $input) && $input['end_at'] !== null && $input['end_at'] !== ''){
        $raw = $input['end_at'];
        if (preg_match('/[zZ]|[+\-]\d{2}:?\d{2}$/', $raw)){
            $dt = new DateTime($raw);
            $dt->setTimezone($tz);
        }else{
            $dt = new DateTime($raw, $tz);
        }
        $end_at = $dt->format('Y-m-d H:i:s');
    }else{
        $end_at = null;
    }
    $stmt = $pdo->prepare('INSERT INTO labors (name,worker_wechat,start_at,end_at,weight,points) VALUES (?,?,?,?,?,?)');
    // log params for debugging
    error_log('create_labor params: '.json_encode([$name,$worker,$start_at,$end_at,$weight,$points]));
    try{
        $stmt->execute([$name,$worker,$start_at,$end_at,$weight,$points]);
        error_log('create_labor success id: '.$pdo->lastInsertId());
    }catch(Exception $e){
        error_log('create_labor error: '.$e->getMessage());
        if ($DEBUG) json_err('insert_failed: '.$e->getMessage(),500);
        json_err('insert_failed',500);
    }
    json_ok(['id'=>$pdo->lastInsertId()]);
}

// update labor
if ($action === 'update_labor' && $_SERVER['REQUEST_METHOD'] === 'POST'){
    require_login();
    $id = intval($input['id'] ?? 0);
    if (!$id) json_err('missing id',400);
    // log raw input for debugging
    $raw = file_get_contents('php://input');
    error_log('update_labor raw: '. $raw);
    error_log('update_labor decoded: '. json_encode($input));
    // query actual columns in labors table to avoid updating non-existent columns
    try{
        $colStmt = $pdo->prepare("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'labors'");
        $colStmt->execute();
        $cols = $colStmt->fetchAll(PDO::FETCH_COLUMN, 0);
    }catch(Exception $e){
        error_log('update_labor get columns error: '.$e->getMessage());
        json_err('db_error',500);
    }
    error_log('labors table columns: '.json_encode($cols));

    // normalize any incoming start_at/end_at to Beijing time so DB remains consistent
    $tz = new DateTimeZone('Asia/Shanghai');
    if (array_key_exists('start_at', $input) && $input['start_at'] !== null && $input['start_at'] !== ''){
        $raw = $input['start_at'];
        if (preg_match('/[zZ]|[+\-]\d{2}:?\d{2}$/', $raw)){
            $dt = new DateTime($raw);
            $dt->setTimezone($tz);
        }else{
            $dt = new DateTime($raw, $tz);
        }
        $input['start_at'] = $dt->format('Y-m-d H:i:s');
    }
    if (array_key_exists('end_at', $input) && $input['end_at'] !== null && $input['end_at'] !== ''){
        $raw = $input['end_at'];
        if (preg_match('/[zZ]|[+\-]\d{2}:?\d{2}$/', $raw)){
            $dt = new DateTime($raw);
            $dt->setTimezone($tz);
        }else{
            $dt = new DateTime($raw, $tz);
        }
        $input['end_at'] = $dt->format('Y-m-d H:i:s');
    }

    $wanted = ['name','start_at','end_at','hours','weight','points','worker_wechat'];
    $sets = [];
    $params = [];
    $ignored = [];
    foreach($wanted as $k){
        if (array_key_exists($k,$input)){
            if (in_array($k, $cols, true)){
                $sets[] = "`$k` = ?";
                $params[] = $input[$k];
            }else{
                $ignored[] = $k;
            }
        }
    }
    if (!empty($ignored)) error_log('update_labor ignored fields (not in table): '.json_encode($ignored));
    if (empty($sets)) json_err('no updatable fields',400);
    $sql = 'UPDATE labors SET '.implode(',', $sets).' WHERE id = ?';
    $params[] = $id;
    error_log('update_labor sql: '.$sql);
    error_log('update_labor params: '.json_encode($params));
    try{
        $stmt = $pdo->prepare($sql);
        $stmt->execute($params);
    }catch(Exception $e){
        error_log('update_labor error: '.$e->getMessage());
        if ($DEBUG) json_err('update_failed: '.$e->getMessage(),500);
        json_err('update_failed',500);
    }
    json_ok([]);
}

// delete labor
if ($action === 'delete_labor' && $_SERVER['REQUEST_METHOD'] === 'POST'){
    require_login();
    $id = intval($input['id'] ?? 0);
    if (!$id) json_err('missing id',400);
    try{
        $stmt = $pdo->prepare('SELECT id, worker_wechat FROM labors WHERE id = ? LIMIT 1');
        $stmt->execute([$id]);
        $row = $stmt->fetch();
    }catch(Exception $e){
        if ($DEBUG) json_err('db_error: '.$e->getMessage(),500);
        json_err('db_error',500);
    }
    if (!$row) json_err('not found',404);
    $user = $_SESSION['user'] ?? null;
    $isAdmin = isset($user['id']) && intval($user['id']) === 1;
    $isOwner = isset($user['wechat']) && $user['wechat'] === $row['worker_wechat'];
    if (!$isAdmin && !$isOwner) json_err('forbidden',403);
    try{
        $del = $pdo->prepare('DELETE FROM labors WHERE id = ?');
        $del->execute([$id]);
    }catch(Exception $e){
        error_log('delete_labor error: '.$e->getMessage());
        if ($DEBUG) json_err('delete_failed: '.$e->getMessage(),500);
        json_err('delete_failed',500);
    }
    json_ok([]);
}

json_err('unknown action',404);

?>
